Skip to content

fix: correctness bugs in flagged-storage, recovery, and docs#516

Open
ndycode wants to merge 1 commit into
mainfrom
fix/bug-sweep
Open

fix: correctness bugs in flagged-storage, recovery, and docs#516
ndycode wants to merge 1 commit into
mainfrom
fix/bug-sweep

Conversation

@ndycode

@ndycode ndycode commented Jun 7, 2026

Copy link
Copy Markdown
Owner

Summary

A parallel multi-agent review sweep over the lib/ tree (rotation/proxy, accounts/storage/recovery, request/auth/refresh, config/manager/usage). I fixed only high-confidence defects with observable wrong behavior, added regression tests, and deliberately left several findings alone after verifying they were false positives or by-design (documented below).

Fixes

1. Flagged-storage silently drops valid enum values (data loss) — lib/storage/flagged-storage.ts

normalizeFlaggedStorage's type guards omitted two members that are part of the type, the Zod schema, and produced at runtime:

  • lastSwitchReason: "manual" (set by the CLI switch command)
  • cooldownReason: "server-error" (produced by failure-policy.ts / runtime-rotation-proxy.ts)

On any load → normalize → save round-trip, these were coerced to undefined, erasing switch/cooldown provenance from flagged records. +2 regression tests.

2. Recovery message-repair could target the wrong message — lib/recovery/storage.ts

findEmptyMessageByIndex probed targetIndex, -1, -2 and returned the first empty message without a role check, unlike its sibling findMessageByIndexNeedingThinking which requires role === "assistant". Added the matching guard so it can't select an unrelated user message. (Export-only/no live caller today — hardening against misuse.)

3. Misleading JSDoc default — lib/rotation.ts

HybridSelectionConfig.freshnessWeight doc said default: 0.1; the actual default is 2.0. A consumer wiring a custom config from the doc would under-weight freshness 20×. Doc corrected.

4. README prerelease link drift — README.md

"Current prerelease" still pointed at v2.3.0-beta.0 after the v2.3.0-beta.1 release. Fixed (asserted by test/documentation.test.ts).

5. New test coverage — test/fs-retry.test.ts

Covers shouldRetryFileOperation across the full FILE_RETRY_CODES set and rejection of non-transient / code-less errors (this predicate had no direct test).

Findings deliberately NOT changed (verified, not bugs)

  • renameTempToPath only retries EPERM/EBUSY (lib/storage.ts): a reviewer flagged this as inconsistent with the module's broader retry set. It is by-design and explicitly testedstorage.test.ts > "throws immediately on non-EPERM/EBUSY errors" asserts EACCES on the final atomic commit-rename fails fast (a real permissions problem, not a transient lock). I made this change, it broke 7 tests, and I reverted it.
  • lastGlobalSwitchAt stamped on every successful request (runtime-rotation-proxy.ts): plausibly intentional "drain-until-exhausted" stickiness, consistent with the recent sequential drain-first feature. Changing it alters core rotation semantics — needs maintainer intent, not a blind fix.
  • Import counts / activeIndex re-clamp (import-export.ts): "skipped vs updated" count semantics are a product judgment encoded in existing tests; the activeIndex concern is masked by load-time normalizeAccountStorage. No observable defect.

Verification

  • npm run build
  • npm run typecheck
  • npm run lint
  • npm test ✅ — 4433 passed, 0 failed, 3 skipped (5 new tests vs. baseline)

Note

Independent of the hono security bump in #515 — that PR can merge separately.

note: greptile review for oc-chatgpt-multi-auth. cite files like lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.

Greptile Summary

this pr fixes three correctness bugs found in a multi-agent sweep: silent data loss in normalizeFlaggedStorage (two missing enum members caused valid lastSwitchReason and cooldownReason values to be coerced to undefined on every save round-trip), a wrong-message selection risk in findEmptyMessageByIndex (no role guard, unlike its sibling), and a 20x wrong freshnessWeight default in the jsdoc.

  • flagged-storage fix: adds \"manual\" to isSwitchReason and \"server-error\" to isCooldownReason, aligning both guards with the full CooldownReason union and AccountMetadataV3 type; two regression tests included.
  • recovery guard: findEmptyMessageByIndex now requires role === \"assistant\" before returning a message id, preventing accidental repair of a user message; no live caller today but no test covers the new branch.
  • docs/tests: corrects jsdoc default for freshnessWeight (0.1 to 2), bumps readme prerelease link, and adds first direct tests for shouldRetryFileOperation across the full FILE_RETRY_CODES set.

Confidence Score: 4/5

safe to merge — all three code changes are narrow, well-scoped fixes with no altered control flow on production-active paths

the flagged-storage and rotation changes are clearly correct and well-tested. the recovery guard is sound but lacks a test for the new branch, and the fs-retry test hardcodes codes instead of iterating the exported set — both are minor coverage gaps that would be cheap to fill.

lib/recovery/storage.ts and test/fs-retry.test.ts would benefit from a second look on test completeness

Important Files Changed

Filename Overview
lib/storage/flagged-storage.ts adds "manual" to isSwitchReason and "server-error" to isCooldownReason, aligning the guards with the full CooldownReason union and AccountMetadataV3 type — genuine data-loss fix with regression tests
lib/recovery/storage.ts adds role === "assistant" guard to findEmptyMessageByIndex, matching the sibling function; no live caller today but correct defensive hardening — no test added for the new guard path
lib/rotation.ts corrects freshnessWeight JSDoc from 0.1 to 2, matching DEFAULT_HYBRID_SELECTION_CONFIG.freshnessWeight = 2.0 — trivial doc-only fix, no logic change
test/flagged-storage.test.ts adds two round-trip regression tests for "manual" and "server-error" enum values; both tests are correct and cover the fixed code paths
test/fs-retry.test.ts new test file for shouldRetryFileOperation; hardcodes retry codes rather than iterating FILE_RETRY_CODES, so future additions to the set won't be automatically exercised
README.md bumps prerelease doc link from v2.3.0-beta.0 to v2.3.0-beta.1; trivial, correct

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[load flagged-storage JSON] --> B[normalizeFlaggedStorage]
    B --> C{isSwitchReason?}
    C -->|rate-limit / initial / rotation / best / restore / manual| D[preserve lastSwitchReason]
    C -->|unknown value| E[coerce to undefined]
    B --> F{isCooldownReason?}
    F -->|auth-failure / network-error / server-error / rate-limit| G[preserve cooldownReason]
    F -->|unknown value| H[coerce to undefined]
    D & G --> I[save normalized record]
    J[findEmptyMessageByIndex] --> K[probe targetIndex -1 -2]
    K --> L{role === assistant?}
    L -->|no| M[skip not a repair target]
    L -->|yes| N{messageHasContent?}
    N -->|empty| O[return message id]
    N -->|has content| P[continue probe]
Loading

Fix All in Codex

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
test/fs-retry.test.ts:14-19
the test hardcodes retry codes instead of deriving them from `FILE_RETRY_CODES`. if a new code is added to the set, `shouldRetryFileOperation` will accept it but this test won't cover it. iterating directly over the exported set makes the test self-updating and also validates the set's size implicitly.

```suggestion
	it("treats every transient lock code as retryable", () => {
		for (const code of FILE_RETRY_CODES) {
			expect(shouldRetryFileOperation(errnoError(code)), code).toBe(true);
		}
	});
```

### Issue 2 of 2
lib/recovery/storage.ts:662-683
**missing vitest coverage for new role guard**

`findEmptyMessageByIndex` now skips user messages via `role !== "assistant"`, but no test exercises that branch. the existing `test/recovery-storage.test.ts` has no case where a user message sits at or near `targetIndex`. if the guard were accidentally reverted or the role string changed, no test would catch it. worth adding at least one case: a messages array where `targetIndex` lands on an empty user message to verify `null` is returned rather than the user message id.

Reviews (1): Last reviewed commit: "fix: correctness bugs in flagged-storage..." | Re-trigger Greptile

Found via a parallel multi-agent review sweep of the lib/ tree. Only
high-confidence defects with observable wrong behavior were fixed;
several reviewer findings were verified as false positives or by-design
and deliberately left alone (see PR notes).

- flagged-storage: the lastSwitchReason/cooldownReason type guards in
  normalizeFlaggedStorage dropped two valid enum members. "manual"
  (lastSwitchReason) and "server-error" (cooldownReason) are part of the
  type, the Zod schema, and are produced at runtime, but the guards
  omitted them — so on any load/normalize/save round-trip those values
  were silently coerced to undefined, erasing switch/cooldown provenance
  from flagged records. Added both to the guards. (+2 regression tests)

- recovery/findEmptyMessageByIndex: add the `role === "assistant"` guard
  that its sibling findMessageByIndexNeedingThinking already has, so the
  index-offset fallback can't select an unrelated user message to repair.
  (Currently export-only with no live caller; hardening to prevent misuse.)

- rotation: HybridSelectionConfig.freshnessWeight JSDoc said "default:
  0.1" while DEFAULT_HYBRID_SELECTION_CONFIG uses 2.0; corrected the doc.

- README: fix the "Current prerelease" link, which still pointed at
  v2.3.0-beta.0 after the v2.3.0-beta.1 release (the doc exists). This is
  what test/documentation.test.ts (release-history) asserts.

- Added test/fs-retry.test.ts covering shouldRetryFileOperation across the
  full FILE_RETRY_CODES set and rejection of non-transient / code-less
  errors.

Verified: build, typecheck, lint, full vitest suite
(4433 passed, 0 failed, 3 skipped). npm audit unaffected.
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0c53bfd6-26b0-451e-b3aa-cd3ce90c49d9

📥 Commits

Reviewing files that changed from the base of the PR and between 98d9819 and 1a792b3.

📒 Files selected for processing (6)
  • README.md
  • lib/recovery/storage.ts
  • lib/rotation.ts
  • lib/storage/flagged-storage.ts
  • test/flagged-storage.test.ts
  • test/fs-retry.test.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (11)
lib/**/*.ts

📄 CodeRabbit inference engine (lib/AGENTS.md)

lib/**/*.ts: All public exports should flow through lib/index.ts or documented package subpaths
Never import from dist/ in source tests or library code
Never suppress type errors

Files:

  • lib/storage/flagged-storage.ts
  • lib/rotation.ts
  • lib/recovery/storage.ts
lib/storage/**/*.ts

📄 CodeRabbit inference engine (lib/AGENTS.md)

lib/storage/**/*.ts: Worktree storage uses resolveProjectStorageIdentityRoot; never derive project pools from raw worktree paths
Never use bare recursive cleanup in Windows-sensitive paths without retry handling

Files:

  • lib/storage/flagged-storage.ts
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Do not use as any, @ts-ignore, or @ts-expect-error type assertions

Files:

  • lib/storage/flagged-storage.ts
  • test/flagged-storage.test.ts
  • test/fs-retry.test.ts
  • lib/rotation.ts
  • lib/recovery/storage.ts
**/*.{ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

Use ESM module syntax exclusively; the project is ESM-only with "type": "module"

Files:

  • lib/storage/flagged-storage.ts
  • test/flagged-storage.test.ts
  • test/fs-retry.test.ts
  • lib/rotation.ts
  • lib/recovery/storage.ts
**/*.{js,ts,mjs,cjs}

📄 CodeRabbit inference engine (README.md)

Support environment variable overrides for configuration: CODEX_MULTI_AUTH_DIR, CODEX_MULTI_AUTH_CONFIG_PATH, CODEX_MODE, CODEX_MULTI_AUTH_RUNTIME_ROTATION_PROXY, CODEX_MULTI_AUTH_APP_ROTATION_IDLE_MS, and others for runtime behavior control

Use async/await patterns for all asynchronous OAuth, HTTP request, and token refresh operations in account management flows

Implement camelCase naming for all JavaScript/TypeScript variables, function names, and object properties throughout the codebase

Enable background Responses mode only when explicitly configured via backgroundResponses setting or CODEX_AUTH_BACKGROUND_RESPONSES=1 environment variable for opt-in stateful routing

Perform best-effort daily npm version checks during normal forwarded Codex startup and print manual upgrade notice only on interactive TTY or when CODEX_MULTI_AUTH_DEBUG=1 is set

Files:

  • lib/storage/flagged-storage.ts
  • test/flagged-storage.test.ts
  • test/fs-retry.test.ts
  • lib/rotation.ts
  • lib/recovery/storage.ts
lib/**

⚙️ CodeRabbit configuration file

focus on auth rotation, windows filesystem IO, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios. check for logging that leaks tokens or emails.

Files:

  • lib/storage/flagged-storage.ts
  • lib/rotation.ts
  • lib/recovery/storage.ts
**

⚙️ CodeRabbit configuration file

**: # PROJECT KNOWLEDGE BASE

Generated: 2026-04-25
Commit: a87e005
Branch: main
Package version: 2.2.0

OVERVIEW

codex-multi-auth is a Codex CLI-first OAuth account manager and optional forwarding wrapper for the official Codex CLI. The installed codex-multi-auth entrypoint handles account-management commands locally, codex-multi-auth-codex forwards official Codex commands through this package's wrapper when explicitly used, and runtime rotation can route live Responses traffic through a localhost account-rotation proxy by default. The plugin-host entrypoint remains exported for compatibility, but the primary product surface is the account manager, optional wrapper, storage, runtime proxy, and repair tooling.

STRUCTURE

./
├── scripts/
│   ├── codex.js              # codex-multi-auth-codex wrapper, official CLI forwarder, shadow CODEX_HOME/runtime proxy setup
│   ├── codex-multi-auth.js   # standalone package CLI entrypoint
│   ├── codex-routing.js      # auth command and compatibility alias routing
│   ├── codex-bin-resolver.js # official Codex binary discovery
│   ├── codex-app-router.js   # persistent localhost router for packaged Codex app bind
│   └── codex-app-launcher.js # reversible user-level app launcher routing helper
├── index.ts                  # optional plugin-host runtime entry
├── lib/                      # core runtime logic (see lib/AGENTS.md)
│   ├── auth/                 # OAuth flow, PKCE, callback server
│   ├── runtime/              # Codex CLI/app integration helpers, app bind, live sync, runtime observability
│   ├── request/              # request transform, SSE, failover, backoff
│   ├── storage/              # path resolution, migrations, backups, restore, import/export
│   ├── codex-cli/            # Codex CLI state sync and writer helpers
│   ├── codex-manager/        # command modules and settings panels
│   ├── prompts/              # model-family prompts, GitHub ETag cache
│   ├── recovery/             # conve...

Files:

  • lib/storage/flagged-storage.ts
  • test/flagged-storage.test.ts
  • test/fs-retry.test.ts
  • README.md
  • lib/rotation.ts
  • lib/recovery/storage.ts
test/**/*.test.ts

📄 CodeRabbit inference engine (test/AGENTS.md)

test/**/*.test.ts: Vitest globals (describe, it, expect) are enabled and should be used without explicit imports
Maintain 80% coverage threshold across statements, branches, functions, and lines
Use removeWithRetry for Windows filesystem cleanup instead of bare fs.rm to handle EBUSY/EPERM/ENOTEMPTY backoff
Use source files in tests, not compiled dist/ files; test the source directly
Do not skip tests without justification; include rationale if a test must be skipped
Relax ESLint rules for test files as specified in eslint.config.js

Files:

  • test/flagged-storage.test.ts
  • test/fs-retry.test.ts
test/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Windows filesystem operations must include retry handling for transient EBUSY, EPERM, and ENOTEMPTY errors where tests cover Windows locks

Files:

  • test/flagged-storage.test.ts
  • test/fs-retry.test.ts
test/**

⚙️ CodeRabbit configuration file

tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.

Files:

  • test/flagged-storage.test.ts
  • test/fs-retry.test.ts
lib/rotation.ts

📄 CodeRabbit inference engine (AGENTS.md)

Runtime rotation is default-on through codexRuntimeRotationProxy; respect CODEX_MULTI_AUTH_RUNTIME_ROTATION_PROXY=0 opt-out

Files:

  • lib/rotation.ts
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: ndycode/codex-multi-auth

Timestamp: 2026-06-07T20:11:13.239Z
Learning: Store credentials locally in `~/.codex/multi-auth/` directory, with accounts saved in `openai-codex-accounts.json` and flagged accounts in `openai-codex-flagged-accounts.json`
Learnt from: CR
Repo: ndycode/codex-multi-auth

Timestamp: 2026-06-07T20:11:13.239Z
Learning: Use OAuth account credentials with explicit ChatGPT account login, account switching, health checks, and local diagnostics
Learnt from: CR
Repo: ndycode/codex-multi-auth

Timestamp: 2026-06-07T20:11:13.239Z
Learning: Implement project-scoped account storage under `~/.codex/multi-auth/projects/<project-key>/` for repo-specific workflows
Learnt from: CR
Repo: ndycode/codex-multi-auth

Timestamp: 2026-06-07T20:11:13.239Z
Learning: Enable default-on loopback-only Responses proxy for live account rotation inside forwarded Codex CLI/app sessions, with optional bridge for `/health`, `/v1/models`, and `/v1/responses` endpoints
Learnt from: CR
Repo: ndycode/codex-multi-auth

Timestamp: 2026-06-07T20:11:13.239Z
Learning: Implement health-aware account selection with quota forecasting, automatic failover, and flagged-account recovery mechanisms
Learnt from: CR
Repo: ndycode/codex-multi-auth

Timestamp: 2026-06-07T20:11:13.239Z
Learning: Disable whole-pool replay by default when every account is rate-limited, use bounded outbound request budget to prevent single prompts from walking full pool, and trigger short cooldown on repeated cross-account 5xx bursts
Learnt from: CR
Repo: ndycode/codex-multi-auth

Timestamp: 2026-06-07T20:11:13.239Z
Learning: Use staggered proactive refresh to reduce background refresh bursts and implement session affinity with live account sync and preemptive quota deferral controls
Learnt from: CR
Repo: ndycode/codex-multi-auth

Timestamp: 2026-06-07T20:11:13.239Z
Learning: Implement three distinct global binaries: `codex-multi-auth` (primary account manager), `codex-multi-auth-codex` (optional wrapper), and `codex-multi-auth-app-launcher` (optional desktop launcher helper)
Learnt from: CR
Repo: ndycode/codex-multi-auth

Timestamp: 2026-06-07T20:11:13.239Z
Learning: Provide explicit command toolkit including: login, status, check, list, switch, forecast, verify-flagged, verify, fix, doctor, uninstall, report, why-selected, usage, monitor, bridge token create, integrations, and rotation status commands
Learnt from: CR
Repo: ndycode/codex-multi-auth

Timestamp: 2026-06-07T20:11:13.239Z
Learning: Maintain local usage ledger in `~/.codex/multi-auth/usage/usage-ledger.jsonl` with project-scoped usage tracking and reporting capabilities
Learnt from: CR
Repo: ndycode/codex-multi-auth

Timestamp: 2026-06-07T20:11:13.239Z
Learning: Support dashboard hotkeys for terminal UI: Up/Down for navigation, Enter for selection, 1-9 for quick switch, `/` for search, `?` for help, `Q` to back/cancel, and account-level actions S/R/E/D
Learnt from: CR
Repo: ndycode/codex-multi-auth

Timestamp: 2026-06-07T20:11:13.239Z
Learning: Keep credentials local with no patching of official Codex binary, and maintain official Codex install path ownership of the `codex` command
Learnt from: CR
Repo: ndycode/codex-multi-auth

Timestamp: 2026-06-07T20:11:13.239Z
Learning: Implement Codex-oriented request/prompt compatibility with strict runtime handling and documented error contracts in API documentation
Learnt from: CR
Repo: ndycode/codex-multi-auth

Timestamp: 2026-06-07T20:11:13.239Z
Learning: Store configuration in JSON format at `~/.codex/multi-auth/settings.json` with support for environment variable overrides via `CODEX_MULTI_AUTH_CONFIG_PATH`
Learnt from: CR
Repo: ndycode/codex-multi-auth

Timestamp: 2026-06-07T20:11:13.239Z
Learning: Validate configuration and state after changes by running `codex-multi-auth status`, `codex-multi-auth check`, and `codex-multi-auth forecast --live`
📚 Learning: 2026-06-07T09:19:57.566Z
Learnt from: CR
Repo: ndycode/codex-multi-auth PR: 0
File: docs/releases/v2.3.0-beta.1.md:0-0
Timestamp: 2026-06-07T09:19:57.566Z
Learning: Applies to docs/releases/**/*.test.ts : Cover account-pool operations with unit tests including the same-email multi-workspace scenario using the real `findMatchingAccountIndex` dedup strategy

Applied to files:

  • test/flagged-storage.test.ts
  • test/fs-retry.test.ts
📚 Learning: 2026-06-07T09:19:57.566Z
Learnt from: CR
Repo: ndycode/codex-multi-auth PR: 0
File: docs/releases/v2.3.0-beta.1.md:0-0
Timestamp: 2026-06-07T09:19:57.566Z
Learning: Applies to docs/releases/**/*callback*.test.ts : Ensure full test coverage for manual-callback classification logic including edge cases like pasted localhost callback URLs

Applied to files:

  • test/flagged-storage.test.ts
  • test/fs-retry.test.ts
📚 Learning: 2026-06-07T09:19:57.566Z
Learnt from: CR
Repo: ndycode/codex-multi-auth PR: 0
File: docs/releases/v2.3.0-beta.1.md:0-0
Timestamp: 2026-06-07T09:19:57.566Z
Learning: Applies to docs/releases/lib/**/*.ts : Keep local copies of shared functions (`resolveAccountSelection`, `persistAccountPool`) in sync with their workspace-aware versions in `lib/runtime/` to avoid behavioral drift

Applied to files:

  • test/flagged-storage.test.ts
📚 Learning: 2026-06-04T06:14:18.093Z
Learnt from: ndycode
Repo: ndycode/codex-multi-auth PR: 510
File: test/scheduling-strategy-config.test.ts:1-1
Timestamp: 2026-06-04T06:14:18.093Z
Learning: In ndycode/codex-multi-auth, do not flag explicit imports from "vitest" (e.g., describe, it, expect, beforeEach/afterEach, etc.) in test files as issues—even if the Vitest config sets `globals: true`. The repo’s established convention is to keep these imports for consistency with neighboring tests; removing them would make files outliers.

Applied to files:

  • test/flagged-storage.test.ts
  • test/fs-retry.test.ts
📚 Learning: 2026-06-04T06:14:24.975Z
Learnt from: ndycode
Repo: ndycode/codex-multi-auth PR: 510
File: test/runtime-rotation-proxy.test.ts:2478-2491
Timestamp: 2026-06-04T06:14:24.975Z
Learning: In ndycode/codex-multi-auth test files (e.g. `test/*.test.ts`), when creating V3 storage fixtures for accounts, it’s an intentional convention to use `as never` for deliberately minimal stored-account objects that only include `refreshToken`, `addedAt`, and `lastUsed`. Do not treat `as never` here as a type-safety problem: optional/other fields are expected to be populated by the runtime during execution, and the cast is used solely to keep the fixture minimal and consistent across existing tests.

Applied to files:

  • test/flagged-storage.test.ts
  • test/fs-retry.test.ts
📚 Learning: 2026-06-07T09:19:57.566Z
Learnt from: CR
Repo: ndycode/codex-multi-auth PR: 0
File: docs/releases/v2.3.0-beta.1.md:0-0
Timestamp: 2026-06-07T09:19:57.566Z
Learning: Applies to docs/releases/**/*cli*.test.ts : Add CLI regression tests for login command features: workspace tracking persistence with `--org <id>`, manual callback state mismatch error handling, and malformed callback URL error handling

Applied to files:

  • test/fs-retry.test.ts
📚 Learning: 2026-06-07T20:01:36.351Z
Learnt from: CR
Repo: ndycode/codex-multi-auth PR: 0
File: README.md:0-0
Timestamp: 2026-06-07T20:01:36.351Z
Learning: Migrate from legacy scoped prerelease `ndycode/codex-multi-auth` by running `npm uninstall -g ndycode/codex-multi-auth` followed by `npm i -g codex-multi-auth`

Applied to files:

  • README.md
📚 Learning: 2026-06-07T20:01:36.351Z
Learnt from: CR
Repo: ndycode/codex-multi-auth PR: 0
File: README.md:0-0
Timestamp: 2026-06-07T20:01:36.351Z
Learning: Use `npm i -g codex-multi-auth` for standard global installation of the codex-multi-auth package

Applied to files:

  • README.md
📚 Learning: 2026-06-07T20:01:36.351Z
Learnt from: CR
Repo: ndycode/codex-multi-auth PR: 0
File: README.md:0-0
Timestamp: 2026-06-07T20:01:36.351Z
Learning: Verify official Codex CLI installation with `codex --version` before installing codex-multi-auth, and confirm codex-multi-auth installation with `codex-multi-auth --version`

Applied to files:

  • README.md
📚 Learning: 2026-06-07T20:01:36.351Z
Learnt from: CR
Repo: ndycode/codex-multi-auth PR: 0
File: README.md:0-0
Timestamp: 2026-06-07T20:01:36.351Z
Learning: Run `codex-multi-auth uninstall` before `npm uninstall` to remove residual artifacts (required for npm7+)

Applied to files:

  • README.md
🔇 Additional comments (4)
lib/storage/flagged-storage.ts (1)

49-50: LGTM!

Also applies to: 56-56

test/flagged-storage.test.ts (1)

32-66: LGTM!

lib/recovery/storage.ts (1)

675-675: Add regression tests for assistant-role eligibility in empty-message recovery

  • Add/extend vitest coverage for the empty-message recovery target selection so only assistant messages qualify and non-assistant roles are rejected, covering the new guard in lib/recovery/storage.ts around lines 675 (and the related helper near 694). Current test/ has no findEmptyMessageByIndex-related matches, so this path may be untested.
test/fs-retry.test.ts (1)

1-34: LGTM!


📝 Walkthrough

Summary

This PR fixes two correctness bugs and one documentation issue with major severity in data persistence and medium severity in message filtering. The flagged-storage fix addresses a data normalization bug where two valid enum members (lastSwitchReason: "manual" and cooldownReason: "server-error") were being coerced to undefined on every load→normalize→save cycle, causing silent data loss. The recovery/storage fix adds a missing role check to findEmptyMessageByIndex to prevent non-assistant messages from being incorrectly returned. Regression tests have been added for the flagged-storage fix (2 tests) and fs-retry behavior (5 tests). Note: The flagged-storage fix is one-way; accounts already saved with undefined values will not be retroactively restored, though the normalization is now correct going forward.

Additional changes:

  • Corrected JSDoc for HybridSelectionConfig.freshnessWeight (documentation-only; actual default is 2.0, not 0.1)
  • Updated README "Current prerelease" link from v2.3.0-beta.0 to v2.3.0-beta.1
  • Added comprehensive test coverage for transient vs. non-transient filesystem error codes

Verification: All builds (build, typecheck, lint) passed; test suite: 4433 passed, 0 failed, 3 skipped (includes 5 new tests).

Walkthrough

version bump to beta.1, recovery storage filters messages by assistant role, flagged storage accepts server-error cooldown reasons with test coverage, fs-retry tests validate transient vs. permanent errno handling, and rotation config docs update freshnessWeight default.

Changes

Release Notes and Storage Validation Updates

Layer / File(s) Summary
Release notes version bump
README.md
Release notes updated from v2.3.0-beta.0 to v2.3.0-beta.1.
Configuration documentation update
lib/rotation.ts
JSDoc for HybridSelectionConfig.freshnessWeight reflects new default of 2 instead of 0.1.
Message recovery role filtering
lib/recovery/storage.ts
findEmptyMessageByIndex now requires assistant role when selecting empty messages by index, filtering out non-assistant candidates.
Flagged storage cooldown reason validation and tests
lib/storage/flagged-storage.ts, test/flagged-storage.test.ts
isCooldownReason now accepts "server-error" and preserves it through normalization. Tests verify round-trip preservation of lastSwitchReason: "manual" and cooldownReason: "server-error".
Filesystem retry test coverage
test/fs-retry.test.ts
New test suite validates shouldRetryFileOperation transient codes (EBUSY, EPERM, EAGAIN, ENOTEMPTY, EACCES), permanent codes (ENOENT, EISDIR, EINVAL, EROFS), and non-error input handling.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested labels

bug

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title follows conventional commits format with 'fix' type, proper scope, and lowercase summary under 72 chars.
Description check ✅ Passed Description comprehensively documents fixes with file locations, regression tests, and verification steps; all core template sections are addressed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/bug-sweep
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/bug-sweep

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

test/flagged-storage.test.ts

Oops! Something went wrong! :(

ESLint: 10.0.0

Error: The 'jiti' library is required for loading TypeScript configuration files. Make sure to install it.
at /node_modules/eslint/lib/config/config-loader.js:145:10
at async loadTypeScriptConfigFileWithJiti (/node_modules/eslint/lib/config/config-loader.js:144:3)
at async loadConfigFile (/node_modules/eslint/lib/config/config-loader.js:265:11)
at async ConfigLoader.calculateConfigArray (/node_modules/eslint/lib/config/config-loader.js:588:23)
at async #calculateConfigArray (/node_modules/eslint/lib/config/config-loader.js:369:19)
at async Promise.all (index 0)
at async findFiles (/node_modules/eslint/lib/eslint/eslint-helpers.js:635:25)
at async ESLint.lintFiles (/node_modules/eslint/lib/eslint/eslint.js:1014:21)
at async Object.execute (/node_modules/eslint/lib/cli.js:386:14)
at async main (/node_modules/eslint/bin/eslint.js:175:19)

test/fs-retry.test.ts

Oops! Something went wrong! :(

ESLint: 10.0.0

Error: The 'jiti' library is required for loading TypeScript configuration files. Make sure to install it.
at /node_modules/eslint/lib/config/config-loader.js:145:10
at async loadTypeScriptConfigFileWithJiti (/node_modules/eslint/lib/config/config-loader.js:144:3)
at async loadConfigFile (/node_modules/eslint/lib/config/config-loader.js:265:11)
at async ConfigLoader.calculateConfigArray (/node_modules/eslint/lib/config/config-loader.js:588:23)
at async #calculateConfigArray (/node_modules/eslint/lib/config/config-loader.js:369:19)
at async Promise.all (index 0)
at async findFiles (/node_modules/eslint/lib/eslint/eslint-helpers.js:635:25)
at async ESLint.lintFiles (/node_modules/eslint/lib/eslint/eslint.js:1014:21)
at async Object.execute (/node_modules/eslint/lib/cli.js:386:14)
at async main (/node_modules/eslint/bin/eslint.js:175:19)


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant